package il.ac.braude.sona.ocsf.server;

import il.ac.braude.sona.constants.ButtonPermission;
import il.ac.braude.sona.constants.Mssg;
import il.ac.braude.sona.constants.P;
import il.ac.braude.sona.constants.TestingParamKit;
import il.ac.braude.sona.constants.P.ViewMssg;
import il.ac.braude.sona.constants.Resources;
import il.ac.braude.sona.constants.Statuses;
import il.ac.braude.sona.entities.ExtensionRequest;
import il.ac.braude.sona.entities.FileTransfer;
import il.ac.braude.sona.entities.LoginKit;
import il.ac.braude.sona.entities.Messege;
import il.ac.braude.sona.entities.PeriodicReport;
import il.ac.braude.sona.entities.SupervisorAction;
import il.ac.braude.sona.entities.User;
import il.ac.braude.sona.entities.Worker;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TimerTask;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;

import javax.swing.JOptionPane;
/**
 * Class in charge of server to be running
 * @author <p>SONA, Sasha,Ofek,Nitzan and Avihai, Group 6,<br>Laboratory in Software Engineering,Ort Braude College.</p>
 *
 */

public class Server extends AbstractServer {
	private TestingParamKit myKit=TestingParamKit.getTestingKit();
	private static DatabaseController dc;
	private static Server instance;
	private HashMap<ConnectionToClient, User> connToUserHash = new HashMap<ConnectionToClient, User>();
	private static final  File serverTempDir = new File(System.getenv("APPDATA") + File.separatorChar +  "SONA");
	/**
	 * Class constructor
	 * @param port port where server located
	 */
	private Server(int port) {
		super(port);
		serverTempDir.mkdirs();
		
	}
	/**
	 * Makes new server instance
	 * @param ip ip
	 * @param username server username
	 * @param password password
	 * @param port port
	 * @throws IOException
	 */
	public static void initInstance(String ip,String username,String password, int port) throws IOException {
		dc = DatabaseController.getInstance(ip,username,password);
		instance=new Server(port);
		instance.listen();
	}
	/**
	 * Returns server instance
	 * @return instance Server
	 */
	public static Server getInstance() {
		if (instance==null) throw new IllegalStateException("initInstance before calling this!");
		return instance;
	}

	@Override
	protected void handleMessageFromClient(Object msg, ConnectionToClient client) {
		try {
			Mssg mssg = (Mssg) msg;
			if (mssg.is(P.login)) 
				handleLogin(client,mssg);
			else {
				User u = connToUserHash.get(client);
				if (u==null) {
					client.sendToClient(new Mssg(mssg.getID(),P.error,"user is not logged in"));
					return;
				}
				if (mssg.is(P.view))
					handleViewRequest(client,u,(ViewMssg) mssg);
				else if (mssg.is(P.ExtensionDecision))
					handleExtensionRequestDecision(client,u, mssg);
				else if (mssg.is(P.create))
					handleCreateRequest(client,u,mssg);
				else if (mssg.is(P.files))
					handleFilesUploadRequest(client,u,mssg);
				else if (mssg.is(P.usersNameByTid) || mssg.is(ButtonPermission.ManagementRegistration))
					handleGetFromUsersTable(client,u,mssg);
				else if (mssg.is(P.systemWorker))
					handleGetSystemsWorker(client,u,mssg);
				else if (mssg.is(P.AppointReqWorkers) || mssg.is(Resources.Strings.AppointManagement))
					handleAppointWorkers(client,u,mssg);
				else if (mssg.is(P.AppointTester))
					handleAppointWorkers(client,u,mssg);
				else if ((mssg.is(P.P_Report.toLowerCase()) || (mssg.is(P.E_Report.toLowerCase())) || (mssg.is(P.D_Report.toLowerCase()))))
					handleDefaultReport(client,u,mssg);
				else if ((mssg.is(P.SupAction)))
					handleSupervisorAction(client, u, mssg);
				else if (mssg.is(P.workerlist) )
					handleWorkerList(client,u,mssg);
				else if (mssg.is(P.EstimateExecutionTime) || mssg.is(P.EstimateSurveyorTime) || mssg.is(P.GetEstimateApprove))
					handleEstimateTime(client,u,mssg);
				else if (mssg.is(P.ApproveExecutionTime) || mssg.is(P.ApproveSurveyorTime))
					handleApproveTime(client,u,mssg);
				else if (mssg.is(P.RequestExtension)){
					try {
						handleExtensionRequest(client,u,mssg);
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}}
				else if (mssg.is(P.GetButtonPermissions))
						handlButtonPermissions(client,u,mssg);
				else if (mssg.is(P.getReports))
					handlePeriodicReports(client,u,mssg);
				else if (mssg.is(P.createSurveyReport) || mssg.is(P.ViewMssg.view_survey_report_fo_rid) || mssg.is(P.AddAdditionalData) || mssg.is(ButtonPermission.EditSurveryReport))
					handleSurveyReport(client,u,mssg);
				else if (mssg.is(ButtonPermission.MakeDecision) || mssg.is(ButtonPermission.ApproveBoardDecision) || mssg.is(P.GetBoardDesision) )
					handleBoardDecision(client,u,mssg);
				else if (mssg.is(ButtonPermission.ApproveModifications))
					handlApproveModifications(client,u,mssg);
				else if (mssg.is(P.extension))
					handleExtensionRequestList(client,u,mssg);
				else if (mssg.is(ButtonPermission.ModificationTested) || mssg.is(P.checkForFailurs) || mssg.is(ButtonPermission.ReportTestFailures))
					handlTesterStage(client,u,mssg);
				else if (mssg.is(ButtonPermission.SupervisorCloseAndNotify) || mssg.is(ButtonPermission.UserConfirm) )
					handlCloseRequest(client,u,mssg);
				else if (mssg.is(ButtonPermission.FreezeRequest) || mssg.is(ButtonPermission.UnFreezeRequest) )
					handlFreezingRequest(client,u,mssg);
				else if (mssg.is(Resources.Strings.UserName))
						handleAddNewUser(client,u,mssg);
				else if (mssg.is(Resources.Strings.DeleteMssg))
					handleDeleteMssg(client,u,mssg);
				

			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

/**
 * Periodic report handle routine
 * @param client 
 * @param u user
 * @param mssg message sent by client
 * @throws IOException
 */
	private void handlePeriodicReports(ConnectionToClient client, User u,
			Mssg mssg) throws IOException {
		ArrayList<PeriodicReport> test = null ;
		try {
			test = dc.getPeriodicReports();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		mssg.setMessege(test);
		client.sendToClient(mssg);
	}
	private void handleDeleteMssg(ConnectionToClient client, User u, Mssg mssg) throws IOException {
		Messege msg = (Messege)mssg.getMessege();		
		  try {
			dc.deleteMssg(msg);
			client.sendToClient(mssg);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Handles extension request decision
	 * @param client 
	 * @param u user
	 * @param mssg message
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	private void handleExtensionRequestDecision(ConnectionToClient client,
			User u, Mssg mssg) throws IOException {
		  HashMap<String,String> test = (HashMap<String,String>)mssg.getMessege();
		
		  try {
			mssg.setMessege(dc.updateExtensionRequestStatus(test));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		  client.sendToClient(mssg);
		  if (test.get("decision").equals("Approve"))
			  MessegesAPI.sendExtensionApprovedMessege(test.get("uid"), test.get("rid"));
		  else
			  MessegesAPI.sendExtensionDecisionMessege(test.get("uid"), test.get("rid"), "DECLINE");
		  
		
	}
/**
 * Handles adding new user to db
 * @param client
 * @param u user id
 * @param mssg 
 * @throws IOException
 */
	@SuppressWarnings("unchecked")
	private void handleAddNewUser(ConnectionToClient client, User u, Mssg mssg) throws IOException{
		try {
			dc.insertNewUser((ArrayList<String>)mssg.getMessege());
			mssg.setMessege(Resources.Strings.Successed);
		    client.sendToClient(mssg);
		} catch (SQLException e) {
			mssg.setType(P.error);
			mssg.setMessege("UserName allready exist, choose other");
			client.sendToClient(mssg);
		}

	}
	
	/**
	 * Handles freezing request request
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handlFreezingRequest(ConnectionToClient client, User u, Mssg mssg)throws IOException {
		if (mssg.is(ButtonPermission.FreezeRequest)){ 
			try {
				dc.freezeRequest((String)mssg.getMessege());
				dc.updateRequestStatus((String)mssg.getMessege(), Statuses.SUSPENDED);
				client.sendToClient(mssg);
				dc.updateSupervisorAction((String)mssg.getMessege(),ButtonPermission.FreezeRequest,u.getID());
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}
		else if (mssg.is(ButtonPermission.UnFreezeRequest)){ 
			try {
				String oldsid=dc.UnfreezeRequest((String)mssg.getMessege());
				dc.updateRequestStatus((String)mssg.getMessege(), oldsid);
				client.sendToClient(mssg);
				notifyStatusChanged((String)mssg.getMessege(), Statuses.SUSPENDED, oldsid);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}
		
	}
	
	/**
	 * Handles close request request
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handlCloseRequest(ConnectionToClient client, User u, Mssg mssg) throws IOException {
		String finishStatus=dc.getCorrectStatus((String)mssg.getMessege());
		if (mssg.is(ButtonPermission.SupervisorCloseAndNotify)){ 
			try {
				dc.updateRequestStatus((String)mssg.getMessege(), Statuses.Closing_User_Request);
				if (finishStatus.equals(Statuses.Closed_Executed))
					dc.notifyOwnerByMail((String)mssg.getMessege(),Resources.Strings.ExecutedMessageToUser);
				else dc.notifyOwnerByMail((String)mssg.getMessege(),Resources.Strings.RejectedMessageToUser);
				client.sendToClient(mssg);
				dc.updateSupervisorAction((String)mssg.getMessege(),ButtonPermission.SupervisorCloseAndNotify,u.getID());
				notifyStatusChanged((String)mssg.getMessege(), Statuses.Closing_Request, Statuses.Closing_User_Request);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}
		else if (mssg.is(ButtonPermission.UserConfirm)){ 
			try {
				dc.updateRequestStatus((String)mssg.getMessege(),finishStatus );
				client.sendToClient(mssg);
				dc.finishExecStage((String)mssg.getMessege(), Statuses.Closing_Request);
				notifyStatusChanged((String)mssg.getMessege(), Statuses.Closing_User_Request, finishStatus);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}
		
	}
	
	/**
	 * Handles extensions report request
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleExtensionRequestList(ConnectionToClient client, User u,
			Mssg mssg) throws IOException {
	     ArrayList<ExtensionRequest> result = dc.loadExtensionRequests();
	     mssg.setMessege(result);
	     client.sendToClient(mssg);
	}
	/**
	 * Handles testing status changes
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handlTesterStage(ConnectionToClient client, User u, Mssg mssg) throws IOException {
		if (mssg.is(ButtonPermission.ModificationTested)){ 
			try {
				dc.updateRequestStatus((String)mssg.getMessege(), Statuses.Closing_Request);
				client.sendToClient(mssg);
				updateExecStages((String)mssg.getMessege(), Statuses.Testing_Started,Statuses.Closing_Request);
				dc.updateEstimateTime((String)mssg.getMessege(),Statuses.Closing_Request,"3");
				dc.startExecStage((String)mssg.getMessege(), Statuses.Closing_Request);
				notifyStatusChanged((String)mssg.getMessege(), Statuses.Testing_Started, Statuses.Closing_Request);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}
		else if (mssg.is(P.checkForFailurs)){
			try {
				mssg.setMessege(dc.getTesterReport((String)mssg.getMessege()));
				client.sendToClient(mssg);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
			}
		}
		else if (mssg.is(ButtonPermission.ReportTestFailures)){
			@SuppressWarnings("unchecked")
			ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
			try {
				list.add(u.getID());
				dc.createFailureReport(list);
				mssg.setMessege(Resources.Strings.Successed);
				client.sendToClient(mssg);
				dc.updateRequestStatus(list.get(1), Statuses.Execution_Started);
				updateExecStages(list.get(1), Statuses.Testing_Started,Statuses.Execution_Started);
				dc.updateEstimateTime(list.get(1),Statuses.Execution_Started,"3");
				dc.startExecStage(list.get(1), Statuses.Execution_Started);
				notifyStatusChanged(list.get(1), Statuses.Testing_Started, Statuses.Execution_Started);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			}
	}
/**
 * Handles approved modifications request
 * @param client
 * @param u
 * @param mssg
 * @throws IOException
 */
	private void handlApproveModifications(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		try {
				dc.updateRequestStatus((String)mssg.getMessege(), Statuses.Testing_Started);
				client.sendToClient(mssg);
				updateExecStages((String)mssg.getMessege(), Statuses.Execution_Started,Statuses.Testing_Started);
				dc.updateEstimateTime((String)mssg.getMessege(),Statuses.Testing_Started,"7");
				dc.startExecStage((String)mssg.getMessege(), Statuses.Testing_Started);
				notifyStatusChanged((String)mssg.getMessege(), Statuses.Execution_Started, Statuses.Testing_Started);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
	}
	/**
	 * Handles board decision update
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleBoardDecision(ConnectionToClient client, User u,Mssg mssg) throws IOException{
		if (mssg.is(ButtonPermission.MakeDecision)){
		@SuppressWarnings("unchecked")
		ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
		try {
			dc.createBoardDecision(list);
			mssg.setMessege(Resources.Strings.Successed);
			client.sendToClient(mssg);
			dc.updateRequestStatus(list.get(2), Statuses.board_has_decision);
			notifyStatusChanged(list.get(2), Statuses.Board_review, Statuses.board_has_decision);
		} catch (SQLException e) {
			mssg.setType(P.error);
			mssg.setMessege("Some Error on SQL query");
			client.sendToClient(mssg);
		}
		}
		else if ( mssg.is(P.GetBoardDesision))
		{
			try {
				mssg.setMessege(dc.getBoardDecision((String)mssg.getMessege()));
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
			}
			client.sendToClient(mssg);
			
		}
		else if (mssg.is(ButtonPermission.ApproveBoardDecision)){
			@SuppressWarnings("unchecked")
			ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
			try {
				dc.approveBoardDecision(list);
				mssg.setMessege(Resources.Strings.Successed);
				client.sendToClient(mssg);
				if (list.get(1).equals(Resources.Strings.Execute)){
				dc.updateRequestStatus(list.get(2), Statuses.Appoint_Tester);
				notifyStatusChanged(list.get(2), Statuses.board_has_decision, Statuses.Appoint_Tester);
				}
				else {				
					dc.updateRequestStatus(list.get(2), Statuses.Closing_Request);
					updateExecStages(list.get(2), Statuses.Board_review,Statuses.Closing_Request);
					dc.updateEstimateTime(list.get(2),Statuses.Closing_Request,"3");
					dc.startExecStage(list.get(2), Statuses.Closing_Request);
					notifyStatusChanged(list.get(2), Statuses.board_has_decision, Statuses.Closing_Request);
				}
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			}
		

	}
	/**
	 * Handles surveyor report update.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleSurveyReport(ConnectionToClient client, User u, Mssg mssg) throws IOException{
		if (mssg.is(P.createSurveyReport)){
		@SuppressWarnings("unchecked")
		ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
		try {
			dc.createSurveyReport(list,u.getID());
			mssg.setMessege(Resources.Strings.SurveyReportSaved);
			client.sendToClient(mssg);
			dc.updateRequestStatus(list.get(5), Statuses.Board_review);
			updateExecStages(list.get(5), Statuses.Surveying_Started,Statuses.Board_review);
			dc.updateEstimateTime(list.get(5),Statuses.Board_review,"7");
			dc.startExecStage(list.get(5), Statuses.Board_review);
			notifyStatusChanged(list.get(5), Statuses.Surveying_Started, Statuses.Board_review);
		} catch (SQLException e) {
			mssg.setType(P.error);
			mssg.setMessege("Some Error on SQL query");
			client.sendToClient(mssg);
		}
		}
		else if ( mssg.is(P.ViewMssg.view_survey_report_fo_rid))
		{
			String rid =(String)mssg.getMessege();
			try {
				mssg.setMessege(dc.getSurveyReportDetails(rid));
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
			}
			client.sendToClient(mssg);
			
		}
		else if (mssg.is(P.AddAdditionalData)){
			@SuppressWarnings("unchecked")
			ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
			try {
				dc.addAdditionalData(list);
				mssg.setMessege(Resources.Strings.Successed);
				client.sendToClient(mssg);
				dc.updateRequestStatus(list.get(0), Statuses.Additional_Surveying);
				updateExecStages(list.get(0), Statuses.Board_review,Statuses.Additional_Surveying);
				dc.updateEstimateTime(list.get(0),Statuses.Additional_Surveying,"3");
				dc.startExecStage(list.get(0), Statuses.Additional_Surveying);
				notifyStatusChanged(list.get(0), Statuses.Board_review, Statuses.Additional_Surveying);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			}
		
		else if (mssg.is(ButtonPermission.EditSurveryReport)){
			@SuppressWarnings("unchecked")
			ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
			try {
				dc.updateSurveyReport(list);
				mssg.setMessege(Resources.Strings.Successed);
				client.sendToClient(mssg);
				dc.updateRequestStatus(list.get(6), Statuses.Board_review);
				updateExecStages(list.get(6), Statuses.Additional_Surveying,Statuses.Board_review);
				dc.updateEstimateTime(list.get(6),Statuses.Board_review,"7");
				dc.startExecStage(list.get(6), Statuses.Board_review);
				notifyStatusChanged(list.get(6), Statuses.Additional_Surveying, Statuses.Board_review);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			}
	}
	/**
	 * Handles extension request request.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 * @throws SQLException
	 */
	@SuppressWarnings("unchecked")
	private void handleExtensionRequest(ConnectionToClient client, User u,Mssg mssg) throws IOException, SQLException {
		ArrayList<String> values = (ArrayList<String>)mssg.getMessege() ;
		values.add(u.getID());
		if(myKit.TestMode)
			myKit.owner = u.getID();
		mssg.setMessege(dc.insertExtensionRequest(values));
		client.sendToClient(mssg);
		
	}
	/**
	 * Handles estimate time request.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleEstimateTime(ConnectionToClient client, User u, Mssg mssg)throws IOException {
		@SuppressWarnings("unchecked")
		ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
		String rid=new String(list.get(1));
		String secValue=new String(list.get(0));
		if (mssg.is(P.EstimateExecutionTime)){
			try {
				dc.updateEstimateTime(rid,Statuses.Execution_Started,secValue);
				client.sendToClient(mssg);
				dc.updateRequestStatus(rid, Statuses.Approve_Execution_Time);
				notifyStatusChanged(rid,Statuses.Estimate_Timeline_Execution, Statuses.Approve_Execution_Time);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}}
		else if(mssg.is(P.EstimateSurveyorTime)) {
			try {
				dc.updateEstimateTime(rid,Statuses.Surveying_Started,secValue);
				client.sendToClient(mssg);
				dc.updateRequestStatus(rid, Statuses.Approve_Surveying_Time);
				notifyStatusChanged(rid,Statuses.Estimate_Timeline_Surveying, Statuses.Approve_Surveying_Time);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			
		}
		else if (mssg.is(P.GetEstimateApprove)){
				if(secValue.equals(Statuses.Approve_Surveying_Time))
				mssg.setMessege(dc.getEstimateTime(rid,Statuses.Surveying_Started));
				else if (secValue.equals(Statuses.Approve_Execution_Time))
					mssg.setMessege(dc.getEstimateTime(rid,Statuses.Execution_Started));
				client.sendToClient(mssg);
				} 
		

	
	}
	/**
	 * Handles approve time request
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleApproveTime(ConnectionToClient client, User u, Mssg mssg)throws IOException {
		String rid=new String((String)mssg.getMessege());
		if (mssg.is(P.ApproveExecutionTime)){
			try {
				dc.updateRequestStatus(rid, Statuses.Execution_Started);
				client.sendToClient(mssg);
				dc.updateSupervisorAction(rid,P.ApproveExecutionTime,u.getID());
				dc.startExecStage(rid, Statuses.Execution_Started);
				notifyStatusChanged(rid,Statuses.Approve_Execution_Time, Statuses.Execution_Started);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}}
		else if(mssg.is(P.ApproveSurveyorTime)) {
			try {
				dc.updateRequestStatus(rid, Statuses.Surveying_Started);
				client.sendToClient(mssg);
				dc.updateSupervisorAction(rid,P.ApproveSurveyorTime,u.getID());
				dc.startExecStage(rid, Statuses.Surveying_Started);
				notifyStatusChanged(rid,Statuses.Approve_Surveying_Time, Statuses.Surveying_Started);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			
		}
	}
	/**
	 * Handles return workers list request
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	public void handleWorkerList(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		ArrayList<Worker> e =dc.getWorkers("'worker'");
		mssg.setMessege(e);
		client.sendToClient(mssg);

	}
	/**
	 * Handles return buttons permissions request.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	public void handlButtonPermissions(ConnectionToClient client, User u,Mssg mssg) throws  IOException {
		@SuppressWarnings("unchecked")
		ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
		String query;
		String extentioncheck=" and p.pid not in (select distinct pid from  premissions p3  where p3.pid='Request Extension' " +
				"and 4<=(select distinct st.date_started+st.estimate_time-CURDATE() from status_execution st where st.rid='"+list.get(2)+"' and st.date_finished is NULL and st.sid=p3.sid  and p3.pid='Request Extension' )" +
				"union" +
				" select p2.pid from extension_request ext2, premissions p2 , change_request ch where ext2.rid='"+list.get(2)+"' and ch.rid=ext2.rid and ch.sid=ext2.sid and p2.sid=ext2.sid and p2.pid='Request Extension')";
		try{
	    if (list.get(3).equals(Statuses.Closing_User_Request)){
				query="select  pid from premissions p,users u, change_request ch " +
						" where ch.rid='"+list.get(2)+"'  and u.uid='"+list.get(1)+"' and u.uid=ch.ownerid" +
								" and ch.sid=p.sid and u.tid=p.tid";
				mssg.setMessege(dc.getButtonPermissions(query));
			}
	    else if (list.get(0).equals("worker")|| (list.get(0).equals("b.member")&&list.get(3).equals(Statuses.Testing_Started))){
			query="select pid from premissions p,users u, worker_type_in_request w, change_request ch " +
					"where ch.rid='"+list.get(2)+"' and ch.rid=w.rid and u.uid='"+list.get(1)+"' and w.uid=u.uid  and w.tid=p.tid " +
							"and ch.sid=p.sid "+extentioncheck;
			mssg.setMessege(dc.getButtonPermissions(query));
		}
		else{
			query="select  pid from premissions p,users u, change_request ch " +
					"where ch.rid='"+list.get(2)+"'  and u.uid='"+list.get(1)+"' " +
							"and ch.sid=p.sid and u.tid=p.tid "+extentioncheck;
			mssg.setMessege(dc.getButtonPermissions(query));
		}
		}catch (SQLException e) {
			mssg.setType(P.error);
			mssg.setMessege("Some Error on SQL query");
		}
		
		client.sendToClient(mssg);
	}
	/**
	 * Handles reports.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	private void handleDefaultReport(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		HashMap<String, String> result = new HashMap<String,String>();
		ArrayList<String> values = (ArrayList<String>)mssg.getMessege();
		if (mssg.is(P.P_Report.toLowerCase())) {
			HashMap<String,HashMap<String,String>> result_p = dc.actionReport(values);
			mssg.setMessege(result_p);
			client.sendToClient(mssg);
			try {
				dc.updatePeriodicReport(values);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (mssg.is(P.E_Report.toLowerCase()))  result = dc.extensionsReport(values);
	    if (mssg.is(P.D_Report.toLowerCase()))  result = dc.totalDelays();
		mssg.setMessege(result);
		client.sendToClient(mssg);
	}
	/**
	 * Handles supervisor actions.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleSupervisorAction(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		ArrayList<SupervisorAction> res = new ArrayList<SupervisorAction>();
		res = dc.supervisorData();
		mssg.setMessege(res);
		client.sendToClient(mssg);
	}

/**
 * Handles appoint workers request.
 * @param client
 * @param u
 * @param mssg
 * @throws IOException
 */
	private void handleAppointWorkers(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		@SuppressWarnings("unchecked")
		ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
		String rid=new String(list.get(0));
		if (mssg.is(P.AppointReqWorkers)) {
			try {
				dc.appointReqWorkers(list);
				client.sendToClient(mssg);
				dc.updateSupervisorAction(rid,P.AppointReqWorkers,u.getID());
				dc.updateRequestStatus(rid, Statuses.Estimate_Timeline_Surveying);
				dc.initNewExecStage(rid, Statuses.Surveying_Started);
				notifyStatusChanged(rid,Statuses.New_Request, Statuses.Estimate_Timeline_Surveying);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
			
		}
		else if (mssg.is(P.AppointTester)) {
			try {
				dc.appointReqTester(list);
				client.sendToClient(mssg);
				dc.updateRequestStatus(list.get(2), Statuses.Estimate_Timeline_Execution);
				updateExecStages(list.get(2),Statuses.Board_review,Statuses.Execution_Started);
				notifyStatusChanged(list.get(2),Statuses.Appoint_Tester, Statuses.Estimate_Timeline_Execution);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}
		else if (mssg.is(Resources.Strings.AppointManagement)) {
			try {
				dc.updateManagementWorkers(list);
				client.sendToClient(mssg);
			} catch (SQLException e) {
				mssg.setType(P.error);
				mssg.setMessege("Some Error on SQL query");
				client.sendToClient(mssg);
			}
		}


	}
/**
 * Handles stages change. 
 * @param rid request id
 * @param fromStatus current status
 * @param toStatus new status
 * @throws SQLException
 */
	private void updateExecStages(String rid, String fromStatus,String toStatus) throws SQLException  {
		dc.finishExecStage(rid, fromStatus);
		dc.initNewExecStage(rid, toStatus);
	}
	
	/**
	 * Handles return worker.
	 * @param client
	 * @param u
	 * @param mssg
	 * @throws IOException
	 */
	private void handleGetSystemsWorker(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		if (mssg.is(P.systemWorker))
			mssg.setMessege(dc.getSystemWorker((String)mssg.getMessege()));
		else{ 

		}
		client.sendToClient(mssg);
	}
/**
 * Handle get data from users.
 * @param client
 * @param u
 * @param mssg
 * @throws IOException
 */
	private void handleGetFromUsersTable(ConnectionToClient client,User u, Mssg mssg)throws IOException  {
		if (mssg.is(P.usersNameByTid))
			mssg.setMessege(dc.getUsersNameWhereTidLike((String)mssg.getMessege()));
		else if (mssg.is(ButtonPermission.ManagementRegistration)){ 
			HashMap<String,String> workers = new  HashMap<String,String>(dc.getUsersNameWhereTidLike("'supervisor'"));
			workers.putAll(dc.getUsersNameWhereTidLike("'b.chairman'"));
			workers.putAll(dc.getUsersNameWhereTidLike("'b.member'"));
			mssg.setMessege(workers);
		}
		client.sendToClient(mssg);
	}

/**
 * Handles files upload
 * @param client
 * @param u
 * @param mssg
 * @throws IOException
 */
	@SuppressWarnings("unchecked")
	private void handleFilesUploadRequest(ConnectionToClient client, User u,Mssg mssg) throws IOException {
		ArrayList<FileTransfer> files = (ArrayList<FileTransfer>) mssg.getMessege();
		for (FileTransfer f : files) {
			try {
				dc.addFileToDatabase(f);
				File writeTo = new File(serverTempDir,f.getChangeRequestId()+"");
				writeTo = new File(writeTo,f.toString());
				f.writeToFile(writeTo);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		mssg.setMessege(null);
		client.sendToClient(mssg);
	}
/**
 * Handles login
 * @param c
 * @param mssg
 * @throws IOException
 */
	@SuppressWarnings("unchecked")
	private void handleLogin(ConnectionToClient c, Mssg mssg) throws IOException {
		Mssg response = mssg;
		try {
			User u = dc.login((ArrayList<String>)mssg.getMessege());
			if (u == null) response = new Mssg(mssg.getID(),P.error,"login info is incorrect.");
			else if (connToUserHash.containsValue(u)) response = new Mssg(mssg.getID(),P.error,"user already logged in");
			else {
				connToUserHash.put(c, u);
				mssg.setMessege(new LoginKit(u,dc.getSystemsAvailable(),MessegesAPI.getAllMessges(u.getID()),dc.getAllPendingRequestDetails(u.getID())));
			}
		} catch (SQLException e) {
			response = new Mssg(mssg.getID(),P.error,"login error");
		}
		c.sendToClient(response);
	}

/**
 * Handles view request query
 * @param c
 * @param u
 * @param mssg
 * @throws IOException
 */
	private void handleViewRequest(ConnectionToClient c, User u, ViewMssg mssg) throws IOException  {	
		if (mssg.getWhat().equals(P.ViewMssg.view_change_request_by_id)) {
			mssg.setMessege(dc.getRequestDetails_new(Long.parseLong(mssg.getWhere())));
		} else if (mssg.getWhat().equals(P.ViewMssg.view_file_by_rid_and_name)){
			File writeFrom = new File(serverTempDir,mssg.getWhere());
			writeFrom = new File(writeFrom,(String) mssg.getMessege());
			try {
				mssg.setMessege(new FileTransfer(writeFrom));
			} catch (IOException e) {
				mssg.setType(P.error);
				mssg.setMessege(e);
			}
		} else if (mssg.getWhat().equals(P.ViewMssg.view_all_requests)) {
			mssg.setMessege(dc.getAllRequestDetails());
		} else if (mssg.getWhat().equals(P.ViewMssg.view_all_pending)) {
			mssg.setMessege(dc.getAllPendingRequestDetails(u.getID()));

		} else if (mssg.getWhat().equals(P.ViewMssg.view_all_mssgs)) {
			mssg.setMessege(MessegesAPI.getAllMessges(u.getID()));

		} else if (mssg.getWhat().equals(P.ViewMssg.viewChangeRequestForMsg)) {
			mssg.setMessege(dc.getRequestDetails(Long.parseLong(mssg.getWhere())));
		}
		
		
		c.sendToClient(mssg);
	}

/**
 * Handles create new change request request
 * @param c
 * @param u
 * @param mssg
 * @throws IOException
 */
	@SuppressWarnings("unchecked")
	private void handleCreateRequest(ConnectionToClient c, User u, Mssg mssg) throws IOException {
		try {
			ArrayList<String> list = (ArrayList<String>) mssg.getMessege();
			long rid = dc.createRequest(list,u.getID());
			mssg.setMessege(rid);
			notifyStatusChanged(rid+"", null, Statuses.New_Request);
		} catch (SQLException e) {
			c.sendToClient(new Mssg(mssg.getID(),P.error,"couldnt create mssg : "+e.getMessage()));
			return;
		}
		c.sendToClient(mssg);
	}






	public static void main(String[] args) throws IOException {
				new File("C:\\sona").mkdirs();
				new File("C:\\sona\\serverlogOut.txt").createNewFile();
				PrintStream p = new PrintStream(new File("C:\\sona\\serverlogOut.txt"));
				System.setErr(p);
				System.setOut(p);
		String ip = JOptionPane.showInputDialog("please enter database server ip");
		String user = JOptionPane.showInputDialog("please enter database user name");
		String pass = JOptionPane.showInputDialog("please enter database password");
		Server.initInstance(ip!=null && ip.length()>0 ? ip : "85.64.56.233",user!=null && user.length()>0 ? user : "root",pass!=null && pass.length()>0 ? pass : "1234",12389);
		Server server = Server.getInstance();
		ScheduleAgent.activate();
		if (server.testDatabaseConnection()) 
			JOptionPane.showMessageDialog(null, "server is now running click ok to quit");
		else 
			{JOptionPane.showMessageDialog(null, "database is not reachable");
			 server.stopListening();
			 ScheduleAgent.deactivate();
			 }
	}

	/**
	 * Returns if there is a connection to data-base
	 * @return true if the connection is ok
	 */
	private boolean testDatabaseConnection() {
		return dc.testConnection();
	}

	/**
	 * call this method whenever you change request status
	 * @param rid request id
	 */
	public void notifyStatusChanged(String rid,String fromStatus,String toStatus) {
		try {
			sendStatusUpdateToClient(dc.getWorkerUIDForChangeRequestNewStatus(rid, toStatus), rid);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
/**
 * Sends message from server to client
 * @param uids 
 * @param rid
 * @throws IOException
 */
	public void sendStatusUpdateToClient(ArrayList<String> uids,String rid) throws IOException {
		Set<Entry<ConnectionToClient, User>> eSet = connToUserHash.entrySet();
		for (Entry<ConnectionToClient, User> e : eSet) {
			for (String uid : uids) {
				if (e.getValue().getID().equals(uid)) {
					Mssg msg = new Mssg(P.server_mssg);
					msg.setMessege(rid);
					e.getKey().sendToClient(msg);
				}
			}
		}
	}
	
	@Override
	protected synchronized void clientDisconnected(ConnectionToClient client) {
		connToUserHash.remove(client);
	}
	@Override
	protected synchronized void clientException(ConnectionToClient client,
			Throwable exception) {
		try {
			client.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		connToUserHash.remove(client);
	}
	Timer timer = new Timer();
	@Override
	protected void clientConnected(final ConnectionToClient client) {
		super.clientConnected(client);
		timer.scheduleAtFixedRate(new TimerTask() {
			
			@Override
			public void run() {
				try {
					client.sendToClient(new Mssg(-1));
				} catch (IOException e) {
					clientDisconnected(client);
				}
			}
		}, 10000,10000);
	}
	
}
